/*-------------------------------------------------------------------------

***************** Modification History ***********************************
   @doc
   @module date.c - Date entry and validation functions |
   @end
   
$Log: /SoftPay/SPK2SIM/Source/Utils/date.c $ 
**************************************************************************

   Copyright (C) 1999 by VeriFone, Inc.

   All rights reserved.  No part of this software may be reproduced,
   transmitted, transcribed, stored in a retrieval system, or translated
   into any language or computer language, in any form or by any means,
   electronic, mechanical, magnetic, optical, chemical, manual or otherwise,
   without the prior written permission of VeriFone, Inc.

---------------------------------------------------------------------------*/
#include <project.h>

#define VSDATE_C

#include <aclconio.h>
#include <stdio.h>
#include <stdlib.h>
#include <acldev.h>
#include <aclstr.h>
#include <string.h>
#include <applidl.h>
#include <actutil.h>

#ifdef DEBUG_VSDATE
#define DEBUG_95
#endif

#include <define.h>
#include <transact.h>
#include <date.h>
#include <gds.h>
#include <util.h>
#include <init.h>
#include <msg.h>
#include <msgfuncs.h>
#include <spdebug.h>
#include <ui.h>
#include <entry.h>
#include <menufunc.h>
#include <tct.h>

/********************************************************************************************* 
* @func void | vdGetCentury |
*               Checks year entered for century & initializes century string
*                 accordingly.
*
* @parm char * | szYear | 
*       The last two digits of the year
*
* @parm char * | szCentury | 
*       The first two digits of the year
*
* @end
**********************************************************************************************/
void vdGetCentury(char* szYear,char* szCentury) {
    int inYear;

    inYear = atoi(szYear);

    if ((inYear >= MIDPOINT_OF_TWENTIETH_CENTURY) && (inYear <= LAST_YEAR_OF_TWENTIETH_CENTURY))
        strlcpy(szCentury, TWENTIETH_CENTURY, CENTURY_SIZE);
    else
        strlcpy(szCentury, TWENTYFIRST_CENTURY, CENTURY_SIZE);

    return;
}

/********************************************************************************************* 
* @func int | inFormatCompleteDateAndTime |
*               Converts a date/time string of form DDMMYY, MMDDYY, YYMM or MMYY,
*                 into a complete date and time string of the form, YYYYMODDHHMISSW.
*
* @parm char * | szCompleteDateAndTime |
*        Buffer to be filled
*
* @parm char * | szDateEntered |
*        String w/ current date/time.
*
* @parm int | inMode |
*       DDMMYY, MMDDYY, YYMM, MMYY. 
*
* @rdesc 
* @flag int | VS_SUCCESS
* @flag int | VS_ERR
* @end
**********************************************************************************************/
int inFormatCompleteDateAndTime(char* szCompleteDateAndTime,char* szDateEntered,int inMode) {
    int status = VS_SUCCESS;
    char szCentury[CENTURY_SIZE + 1],
    szTempDateBuff[DATE_SIZE + 1],
    szTodaysDate[COMPLETE_DATE_AND_TIME_SIZE + 1];
    char szDummyMessage[MESSAGE_SIZE + 1];

    SVC_CLOCK(GET_CLOCK, (char *) szTodaysDate, COMPLETE_DATE_AND_TIME_SIZE);

    switch (inMode) {
    case DDMMYY:
        vdGetCentury(&(szDateEntered[4]), szCentury);
        vdGetMessageFromFile(FORMAT_DATE1_MSG, szDummyMessage);
        sprintf(szCompleteDateAndTime, szDummyMessage, szCentury, &(szDateEntered[4]), &(szDateEntered[2]), &(szDateEntered[0]), &(szTodaysDate[INDEX_TO_TIME]), &(szTodaysDate[INDEX_TO_WDAY]));
        break;

    case MMDDYY:
        vdGetCentury(&(szDateEntered[4]), szCentury);
        vdGetMessageFromFile(FORMAT_DATE2_MSG, szDummyMessage);
        sprintf(szCompleteDateAndTime, szDummyMessage, szCentury, &(szDateEntered[4]), &(szDateEntered[0]), &(szDateEntered[2]), &(szTodaysDate[INDEX_TO_TIME]), szTodaysDate[INDEX_TO_WDAY]);
        break;

    case YYMM:
        sprintf(szTempDateBuff, "%s%s", &(szDateEntered[2]), &(szDateEntered[0]));
        vdGetCentury(&(szTempDateBuff[2]), szCentury);
        vdGetMessageFromFile(FORMAT_DATE2_MSG, szDummyMessage);
        sprintf(szCompleteDateAndTime, szDummyMessage, szCentury, &(szTempDateBuff[2]), &(szTempDateBuff[0]), &(szTodaysDate[INDEX_TO_DAY]), &(szTodaysDate[INDEX_TO_TIME]), szTodaysDate[INDEX_TO_WDAY]);
        break;

    case MMYY:
        vdGetCentury(&(szDateEntered[2]), szCentury);
        vdGetMessageFromFile(FORMAT_DATE2_MSG, szDummyMessage);
        sprintf(szCompleteDateAndTime, szDummyMessage, szCentury, &(szDateEntered[2]), &(szDateEntered[0]), &(szTodaysDate[INDEX_TO_DAY]), &(szTodaysDate[INDEX_TO_TIME]), szTodaysDate[INDEX_TO_WDAY]);
        break;

    default:
        status = VS_ERR;
    }
    return status;
}
/********************************************************************************************* 
* @func void | vdDelay |
*               Calls SVC_WAIT which pauses processing.
*
* @parm int | inMilliSec | 
*       Wait time in milliseconds
*
* @end
**********************************************************************************************/

void vdDelay(int inMilliSec) {
    SVC_WAIT(inMilliSec);

    return;
}
/********************************************************************************************* 
* @func void | vdGetTime |
*               Gets the time in HHMMSS format. The varible pchTime should be allocated
*                  outside, the size should be 7 bytes.
*
* @parm char * | pchTime | 
*       Buffer to receive the time string
*
* @end
**********************************************************************************************/
void vdGetTime(char* pchTime) {
    char Buffer[COMPLETE_DATE_AND_TIME_SIZE + 1];

    if (SVC_CLOCK(GET_CLOCK, (char *) Buffer, COMPLETE_DATE_AND_TIME_SIZE) != COMPLETE_DATE_AND_TIME_SIZE)
        VSAbort(125);

    memcpy(pchTime, &(Buffer[8]), TIME_SIZE);

    pchTime[TIME_SIZE] = NULL_CH;

    return;
}

/********************************************************************************************* 
* @func void | vdGetDate |
*               Gets the date.  The varible pchDate should be allocated
*                  outside.
*
* @parm char * | pchDate | 
*       Buffer to receive the date string
*
* @parm int |inMode|
*       Format of the date DDMMYY, MMDDYY, YYYYMMDD, YYMMDD(default)
*
* @end
**********************************************************************************************/
void vdGetDate(char* pchDate,int inMode) {
    char Buffer[COMPLETE_DATE_AND_TIME_SIZE + 1];
    int inDateLen;

    if (SVC_CLOCK(GET_CLOCK, (char *) Buffer, COMPLETE_DATE_AND_TIME_SIZE) != COMPLETE_DATE_AND_TIME_SIZE)
        VSAbort(125);

    switch (inMode) {
    case DDMMYY:
        memcpy(pchDate, &(Buffer[6]), 2);
        memcpy(&pchDate[2], &(Buffer[4]), 2);
        memcpy(&pchDate[4], &(Buffer[2]), 2);
        inDateLen = DATE_SIZE;
        break;

    case MMDDYY:
        memcpy(pchDate, &(Buffer[4]), 4);
        memcpy(&pchDate[4], &(Buffer[2]), 2);
        inDateLen = DATE_SIZE;
        break;

    case YYYYMMDD:
        memcpy(pchDate, Buffer, DATE_SIZE + CENTURY_SIZE);
        inDateLen = DATE_SIZE + CENTURY_SIZE;
        break;

    case YYMMDD:
    default:
        memcpy(pchDate, &(Buffer[2]), DATE_SIZE);
        inDateLen = DATE_SIZE;
    }

    pchDate[inDateLen] = NULL_CH;

    return;
}

/********************************************************************************************* 
* @func int | inIsDateInRange |
*               Check that the given date falls w/in a range relative to the
*                 POS's date.
*
* @parm char * | date_entered |
*        Date to check
*
* @parm int | min_val |
*        Number of days prior to the POS date that the day is valid
*
* @parm int | max_val |
*        Number of days after the POS date that the day is valid
*
* @parm int | date_format |
*       DDMMYY, MMDDYY, YYMM, MMYY. 
*
* @rdesc 
* @flag int | VS_SUCCESS if date is within range
* @flag int | VS_ERR if date is not within range
* @end
**********************************************************************************************/
int inIsDateInRange(char* date_entered,int min_val,int max_val,int date_mode) {
    int status = VS_SUCCESS;
    int POSyear,
    Enteredyear,
    mon,
    day,
    hour,
    min,
    sec,
    wday = 0,
    POSDate,
    EnteredDate,
    EndOfYearDate;
    char szCompleteDateAndTime[COMPLETE_DATE_AND_TIME_SIZE + 1];
    unsigned char * chNull = 0;

    if (inFormatCompleteDateAndTime(szCompleteDateAndTime, date_entered, date_mode) == VS_ERR)
        return VS_ERR;

    if (clock2int(NO_CLOCK_HANDLE(unsigned char *)szCompleteDateAndTime, &Enteredyear, &mon, &day, &hour, &min, &sec, &wday) < 0)
        return VS_ERR;

    EnteredDate = julian_date(Enteredyear, mon, day);

    if (clock2int(NO_CLOCK_HANDLE chNull, &POSyear, &mon, &day, &hour, &min, &sec, &wday) < 0)
        return VS_ERR;

    POSDate = julian_date(POSyear, mon, day);

    if (POSyear == Enteredyear) {
        if (EnteredDate > (POSDate + max_val))
            status = VS_ERR;
        else {
            if ((POSDate - EnteredDate) > min_val)
                status = VS_ERR;
        }
    } else {
        if (Enteredyear > POSyear) {
            EndOfYearDate = julian_date(POSyear, 12, 31);
            if ((EndOfYearDate + EnteredDate) - POSDate > max_val)
                status = VS_ERR;
        } else {
            EndOfYearDate = julian_date(Enteredyear, 12, 31);
            if ((EndOfYearDate + POSDate) - EnteredDate > min_val)
                status = VS_ERR;
        }
    }

    return status;
}

/********************************************************************************************* 
* @func int | inValidateExpDate |
*            Check the validity of the date. The function addresses the 21st Century 
*            and leap years. Also, the expiration day-of-month computed to be the 
*            last day of the given month.
*
* @parm char * | szDateEntered |
*        Pointer to buffer containing date
*
* @rdesc 
* @flag int | VS_SUCCESS
* @flag int | VS_ERR
* @end
**********************************************************************************************/
int inValidateExpDate(char* szDateEntered) {
    int inEnteredDate,
    inPOSDate,
    inWday,
    inSec,
    inMin,
    inHour,
    inDay,
    inMon,
    inPOSYear,
    inEnteredYear,
    inStatus = VS_SUCCESS;
    char szCentury[CENTURY_SIZE + 1],
    szTempDate[DATE_SIZE + 1],
    szPOSDateAndTime[COMPLETE_DATE_AND_TIME_SIZE + 1];

    pdebug(("--inValidateExpDate--"));

    sprintf(szTempDate, "%.2s%.2s", &(szDateEntered[2]), &(szDateEntered[0]));
    vdGetCentury(&(szTempDate[2]), szCentury);
    pdebug(("Century = %2s", szCentury));

    sprintf(szTempDate, "%s%.2s", szCentury, &(szDateEntered[0]));
    pdebug(("TempDate = %s", szTempDate));

    inMon = atoi(&(szDateEntered[2]));
    if ((inMon > MAX_MONTHS_IN_YEAR) || (inMon < MIN_MONTHS_IN_YEAR)) {
        vdSGErrorMessage(INV_DATE_ERR_MSG);
        return VS_ERR;
    }

    inEnteredYear = atoi(szTempDate);
    inDay = month_end(inMon, inEnteredYear);
    inEnteredDate = julian_date(inEnteredYear, inMon, inDay);

    SVC_CLOCK(GET_CLOCK, (char *) szPOSDateAndTime, COMPLETE_DATE_AND_TIME_SIZE);
    if (clock2int(NO_CLOCK_HANDLE(unsigned char *)szPOSDateAndTime, &inPOSYear, &inMon, &inDay, &inHour, &inMin, &inSec, &inWday) < 0) {
        vdSGErrorMessage(EXP_CARD_ERR_MSG21);
        return VS_ERR;
    }

    inPOSDate = julian_date(inPOSYear, inMon, inDay);
    pdebug(("inPOSYear = %d", inPOSYear));
    pdebug(("inEnteredYear = %d", inEnteredYear));
    if (inPOSYear > inEnteredYear)
        inStatus = VS_ERR;
    else if (inPOSYear == inEnteredYear) {
        if (inPOSDate > inEnteredDate)
            inStatus = VS_ERR;
    }
    if (inStatus == VS_ERR)
        vdSGErrorMessage(EXP_CARD_ERR_MSG21);
    return(inStatus);
}

/********************************************************************************************* 
* @func int | inValidateOrigDate |
*            Check the validity of the original transaction date. 
*
* @parm char * | szDateEntered |
*        Pointer to buffer containing date
*
* @rdesc 
* @flag int | VS_SUCCESS
* @flag int | VS_ERR
* @end
**********************************************************************************************/
int inValidateOrigDate(char* szDateEntered) {
    int inDay,
    inMon,
    inLastDay,
    inYear;
    char szTempDate[DATE_SIZE + 1];
    char szCurDate[10];

    pdebug(("--inValidateOrigDate--"));


    vdGetDate(szCurDate, YYYYMMDD);
    szCurDate[4] = '\0';
    inYear = atoi(szCurDate);

    pad(szDateEntered, szDateEntered, '0', 4, RIGHT);
    memcpy(szTempDate, szDateEntered, 2);
    szTempDate[2] = '\0';
    pdebug(("TempDate = %s", szTempDate));

    inMon = atoi(szTempDate);
    if ((inMon > MAX_MONTHS_IN_YEAR) || (inMon < MIN_MONTHS_IN_YEAR)) {
        vdSGErrorMessage(INV_DATE_ERR_MSG);
        return VS_ERR;
    }

    memcpy(szTempDate, &szDateEntered[2], 2);
    szTempDate[2] = '\0';
    pdebug(("TempDate = %s", szTempDate));

    inDay = atoi(szTempDate);
    if (inMon > 12 || inMon < 1) {
        vdSGErrorMessage(INV_DATE_ERR_MSG);
        return (VS_ERR);
    }
    inLastDay = month_end(inMon, inYear);
    if (inDay > inLastDay || inDay < 1) {
        vdSGErrorMessage(INV_DATE_ERR_MSG);
        return (VS_ERR);
    }
    return(VS_SUCCESS);
}
/********************************************************************************************* 
* @func int | inValChTime |
*            Check the validity of the time. 
*
* @parm TRANSACTION_OBJECT  | *pobTran
*       Transaction object
*
* @parm char * | pchTime |
*        Pointer to buffer containing time
*
* @parm int | inTimeLen
*       Size of the buffer containing the time
*
* @rdesc 
* @flag int | VS_SUCCESS
* @flag int | VS_ERR
* @end
**********************************************************************************************/
int inValChTime(TRANSACTION_OBJECT* pobTran,char* pchTime,int inTimeLen) {
    char szTempTime[2 + 1];
    char szTimeIn[TIME_SIZE + 1];

    int inMins = 0;
    int inHrs = 0;
    int inSecs = 0;


    /** /pdebug(("--inValChTime--"));*/

    vdSGErrorMessage(0L);


    /*
     *  check parms
     */
    if ((!pobTran) || (!pchTime) || ((inTimeLen != 4) && (inTimeLen != 6))) {
        vdSGErrorMessage(INV_TIME_ERR_MSG);
        return(VS_ERR);
    }  


    /*
     *  check the size of
     *  the entire date string
     */
    strncpy(szTimeIn, pchTime, (sizeof(szTimeIn) - 1));
    szTimeIn[(sizeof(szTimeIn) - 1)] = NULL_CH;
    if ((strlen(szTimeIn) != 4) && (strlen(szTimeIn) != 6)) {
        vdSGErrorMessage(INV_TIME_ERR_MSG);
        return(VS_ERR);
    }    

    if (strlen(szTimeIn) == 4) {
        /*
         *  Allow user to
         *  omit seconds if
         *  so desired....
         */
        szTimeIn[4] = '0';
        szTimeIn[5] = '0';
        szTimeIn[6] = NULL_CH;
    }


    /*
     *  get the 2-digit hours
     */
    memcpy(szTempTime, szTimeIn, (sizeof(szTempTime) - 1));
    szTempTime[(sizeof(szTempTime) - 1)] = NULL_CH;
    inHrs = atoi(szTempTime);

    /*
     *  get the 2-digit minutes
     */
    memcpy(szTempTime, &szTimeIn[2], (sizeof(szTempTime) - 1));
    szTempTime[(sizeof(szTempTime) - 1)] = NULL_CH;
    inMins = atoi(szTempTime);

    /*
     *  get the 2-digit seconds
     */
    memcpy(szTempTime, &szTimeIn[4], (sizeof(szTempTime) - 1));
    szTempTime[(sizeof(szTempTime) - 1)] = NULL_CH;
    inSecs = atoi(szTempTime);


    if ((inHrs < 0) || (inHrs > 23)) {
        vdSGErrorMessage(INV_TIME_ERR_MSG);
        return(VS_ERR);
    }

    if ((inMins < 0) || (inMins > 59)) {
        vdSGErrorMessage(INV_TIME_ERR_MSG);
        return(VS_ERR);
    }

    if ((inSecs < 0) || (inSecs > 59)) {
        vdSGErrorMessage(INV_TIME_ERR_MSG);
        return(VS_ERR);
    }

    strncpy(pchTime, szTimeIn, (sizeof(szTimeIn) - 1));
    pchTime[(sizeof(szTimeIn) - 1)] = NULL_CH;

    return(VS_SUCCESS);
} /* End of inValChTime() */

/********************************************************************************************* 
* @func int | inVal8ChDate |
*            Check the validity of the date. 
*
* @parm TRANSACTION_OBJECT  | *pobTran
*       Transaction object
*
* @parm char * | pchDate |
*        Pointer to buffer containing date
*
* @parm int | inDateLen
*       Size of the buffer containing the date
*
* @rdesc 
* @flag int | VS_SUCCESS
* @flag int | VS_ERR
* @end
**********************************************************************************************/
int inVal8ChDate(TRANSACTION_OBJECT* pobTran,char* pchDate,int inDateLen) {
    char szTempDate[4 + 1];
    char szDateIn[DATE_SIZE + 2 + 1];

    int inDay = 0;
    int inMon = 0;
    int inLastDay = 0;
    int inYear = 0;


    /** /pdebug(("--inVal8ChDate--"));*/

    vdSGErrorMessage(0L);

    /*
     *  check parms
     */
    if ((!pobTran) || (!pchDate) || (inDateLen != 8)) {
        vdSGErrorMessage(INV_DATE_ERR_MSG);
        return(VS_ERR);
    }  


    /*
     *  check the size of
     *  the entire date string
     */
    strncpy(szDateIn, pchDate, (sizeof(szDateIn) - 1));
    szDateIn[(sizeof(szDateIn) - 1)] = NULL_CH;
    if (strlen(szDateIn) != 8) {
        vdSGErrorMessage(INV_DATE_ERR_MSG);
        return(VS_ERR);
    }    


    /*
     *  get the 2-digit month
     */
    memcpy(szTempDate, szDateIn, (sizeof(szTempDate) - 3));
    szTempDate[(sizeof(szTempDate) - 3)] = NULL_CH;
    inMon = atoi(szTempDate);

    /*
     *  get the 2-digit day
     */
    memcpy(szTempDate, &szDateIn[2], (sizeof(szTempDate) - 3));
    szTempDate[(sizeof(szTempDate) - 3)] = NULL_CH;
    inDay = atoi(szTempDate);

    /*
     *  get the 4-digit year
     */
    memcpy(szTempDate, &szDateIn[4], (sizeof(szTempDate) - 1));
    szTempDate[(sizeof(szTempDate) - 1)] = NULL_CH;
    inYear = atoi(szTempDate);


    /*
     *  use subset of ALLOWED year range
     *  specified in Omni 300 Series 
     *  Terminal, Programmer's Manual,
     *  Volume 1, page 8-61.
     *  
     */
    if ((inYear < 1998) || (inYear > 2088)) {
        vdSGErrorMessage(INV_DATE_ERR_MSG);
        return(VS_ERR);
    }

    if ((inMon < 1) || (inMon > 12)) {
        vdSGErrorMessage(INV_DATE_ERR_MSG);
        return(VS_ERR);
    }

    if ((inDay < 1) || (inDay > 31)) {
        vdSGErrorMessage(INV_DATE_ERR_MSG);
        return(VS_ERR);
    }


    inLastDay = month_end(inMon, inYear);
    if (inDay > inLastDay) {
        vdSGErrorMessage(INV_DATE_ERR_MSG);
        return (VS_ERR);
    }

    return(VS_SUCCESS);
} /* End of inVal8ChDate() */

/********************************************************************************************* 
* @func int | inEnterSysChron |
*            Obtains the system date or time from the user. 
*
* @parm TRANSACTION_OBJECT  | *pobTran
*       Transaction object
*
* @parm int | inOpCode
*       0 = Set the time, 1 = Set the date
*
* @rdesc 
* @flag int | VS_SUCCESS
* @flag int | VS_ERR
* @end
**********************************************************************************************/

int inEnterSysChron(TRANSACTION_OBJECT* pobTran,int inOpCode) {
    int inResult = VS_SUCCESS;
    char szChronBuf[DATE_SIZE + 2 + 1];
    long lnEntryMsg = 0L;
    int inEntrySize = 0;

    char* pchDate = (char*) 0;
    char* pchTime = (char*) 0;

    PFI_TO_PSZ_INT inValidator = (PFI_TO_PSZ_INT) 0;

    if ((pobTran) && ((inOpCode == 0) || (inOpCode == 1))) {
        if (inOpCode == 0) {
            inValidator = inVal8ChDate;
            lnEntryMsg = SYSDATE_MSG;
            inEntrySize = 8;
            pchDate = szChronBuf;
            pchTime = (char *) 0;
        } else {
            inValidator = inValChTime;
            lnEntryMsg = SYSTIME_MSG;
            inEntrySize = 6;
            pchTime = szChronBuf;
            pchDate = (char *) 0;
        }


        do {
            vdSetNextLineEntry(); /* force entry on line after prompt */            
            memset(szChronBuf, NULL_CH, sizeof(szChronBuf));
            inResult = 0;
            inResult = inEnterWithMessage(lnEntryMsg, FALSE, /* SCROLL_DISPLAY_FALSE */
                                   szChronBuf, 0, /* INPUT_NUMS           */
                                   inEntrySize, NULL_PFI);


            if ((inResult == 0)) {
                vdClearNonTitleLines();
                return(VS_SUCCESS);
            } else if ((inResult == VS_ESCAPE) || (act_kbd_pending_test(KEY_CANCEL))) {
                vdClearNonTitleLines();
                return(VS_ESCAPE);
            } else if (inResult >= 0) {
                vdDisableClearKey(VS_TRUE);                
                if ((inResult = inValidator(pobTran, szChronBuf, inEntrySize)) == VS_SUCCESS)
                    inResult = inPackDateTime(pchDate, pchTime);
                else {
                    beep(2000); /* ERR_BEEP() */
                }
                vdDisableClearKey(VS_FALSE);
            }
        } while (!act_kbd_pending_test(KEY_CANCEL) && inResult != VS_SUCCESS);

        vdClearNonTitleLines();
    }

    if (inResult != VS_SUCCESS) {
        if (lnGGErrorMessage())
            vdDisplayMessageFromFile(lnGGErrorMessage(), ERROR_MSG);
    }

    return (inResult);
} /* End of inEnterSysChron () */

/********************************************************************************************* 
* @func int | inPackDateTime |
*               Sets the terminal clock with the time and date entered
*
* @parm char * | pchDate |
*        Pointer to buffer containing the date
*
* @parm char * | pchTime |
*        Pointer to buffer containing the time
*
* @rdesc 
* @flag int | VS_SUCCESS
* @flag int | VS_ERR
* @end
**********************************************************************************************/
int inPackDateTime(char* pchDate,char* pchTime) {
    char szGnomon[16 + 1];
    char szScrap[16 + 1];

    int inRdWr = 0;
    int inPos = 0;
    int inSize = 0;


    if ((!pchDate) && (!pchTime)) {
        vdSGErrorMessage(INV_DATETIME_ERR_MSG);
        return (VS_ERR);
    }

    memset(szGnomon, NULL_CH, sizeof(szGnomon));
    memset(szScrap, NULL_CH, sizeof(szScrap));

    if (pchDate) {
        /* yyyymmdd */

        strncpy(&szGnomon[inPos], &pchDate[4], (inSize = 4)); /* yyyy */
        inPos += inSize;
        strncpy(&szGnomon[inPos], &pchDate[0], (inSize = 2)); /* mm   */
        inPos += inSize;
        strncpy(&szGnomon[inPos], &pchDate[2], (inSize = 2)); /* dd   */
        inPos += inSize;
        szGnomon[inPos] = NULL_CH;
    } else {
        /* must read current date */
        inRdWr = SVC_CLOCK(GET_CLOCK, (char *) szGnomon, 15);
        szGnomon[8] = NULL_CH;
        if (inRdWr != 15) {
            vdSGErrorMessage(INV_DATETIME_ERR_MSG);
            return (VS_ERR);
        }

        inPos = 8;
    }

    if (pchTime) {
        /* hhmmss   */

        strncpy(&szGnomon[inPos], &pchTime[0], (inSize = 2)); /* hh   */    
        inPos += inSize;
        strncpy(&szGnomon[inPos], &pchTime[2], (inSize = 2)); /* mm   */    
        inPos += inSize;
        strncpy(&szGnomon[inPos], &pchTime[4], (inSize = 2)); /* mm   */    
        inPos += inSize;
        szGnomon[inPos] = NULL_CH;
    } else {
        /* must read current time */
        inRdWr = SVC_CLOCK(GET_CLOCK, (char *) szScrap, 15);
        szScrap[14] = NULL_CH;
        if (inRdWr != 15) {
            vdSGErrorMessage(INV_DATETIME_ERR_MSG);
            return (VS_ERR);
        }

        strncpy(&szGnomon[inPos], &szScrap[8], (inSize = 6)); /* hhmmss   */    
        inPos += inSize;
        szGnomon[inPos] = NULL_CH;
    }

    if (strlen(szGnomon) != 14) {
        vdSGErrorMessage(INV_DATETIME_ERR_MSG);
        return (VS_ERR);
    } else {
        inRdWr = SVC_CLOCK(SET_CLOCK, (char *) szGnomon, 14);
        if (inRdWr != 14) {
            vdSGErrorMessage(INV_DATETIME_ERR_MSG);
            return (VS_ERR);
        }
    }

    return(VS_SUCCESS);
}

/********************************************************************************************* 
* @func int | inHourlyNotify |
*            Hourly Notification, if flag is set, sound tone once
*               each hour on the minute value specified. 
*
* @parm TRANSACTION_OBJECT  | *pobTran
*       Transaction object
*
* @rdesc 
* @flag int | VS_SUCCESS
* @flag int | VS_ERR
* @end
**********************************************************************************************/

int inHourlyNotify(TRANSACTION_OBJECT* pobTran) {
    char chTimeBuff[FORMATTED_TIME_SIZE + 1];
    static VS_BOOL fHToneDone = FALSE;

    if (fGetHourlyNotify() == VS_TRUE) {
        vdGetTime(chTimeBuff);
        if (chars2int(chTimeBuff + 2, 2) == inGetNotifyTime()) {
            if (fHToneDone == FALSE) {
                vdBeep();  
                fHToneDone = TRUE;
            }
        } else
            fHToneDone = FALSE;
    }

    return (VS_SUCCESS);
}


#undef VSDATE_C

